with ada.text_io;
with v_string; use v_string;
with ada.sequential_io;

package body authentication is

    package t_io renames ada.text_io;
    package user_io is new ada.sequential_io (user);

    --global variables
    currentUser : user;
    null_user : constant user := user'(-1, v_string.v_null, v_string.v_null);
    numUsers : Integer;
    nextID : Integer;
    users : userArray;
    initialized : boolean := false;
    dataFile : user_io.file_type;
    dataFileName : constant string := "users.dat";
    backupFileName : constant string := "users_backup.dat";

    
    
    procedure init is
    begin
	begin
	    user_io.open(dataFile, user_io.in_file, dataFileName);
	    numUsers := 0;
	    nextID := 0;
	    loop
		exit when user_io.end_of_file(dataFile) or numUsers = MaxUsers;
		numUsers := numUsers + 1;
		user_io.read(dataFile, users(numUsers));
		if users(numUsers).ID > nextID then
		    nextID := users(numUsers).ID;
		end if;
	    end loop;
	    nextID := nextID + 1;
	    user_io.close(dataFile);
	exception
	    when user_io.name_error =>
		t_io.put_line("creating file");
		user_io.create(dataFile, user_io.in_file, dataFileName);
		numUsers := 0;
	end;
	initialized := true;
    end init;

    
    procedure createUser (username : in vstring; password : in vstring) is
    begin
	if initialized = false then
	    init;
	end if;
	for i in 1..numUsers loop
	    if vcompare(username, users(i).username) then
		raise create_user_error;
	    end if;
	end loop;
	if numUsers < MaxUsers then
	    numUsers := numUsers + 1;
	    users(numUsers) := user'(ID => nextID, username => username, password => password);
            user_io.open(dataFile, user_io.append_file, dataFileName);
	    user_io.write(dataFile, users(numUsers));
	    user_io.close(dataFile);
	    nextID := nextID + 1;
	else
	    raise create_user_error;
	end if;
    end createUser;

    function deleteUser (IDToDelete : in Integer) return Boolean is
	index : Integer;
    begin
	if initialized = false then
	    init;
	end if;
	--get array index
	index := -1;
	for i in 1..numUsers loop
	    if users(i).ID = IDToDelete then
		index := i;
		exit;
	    end if;
	end loop;
	
	if index < 0 then
	    return false;
	end if;

	users(index) := users(numUsers);
	numUsers := numUsers - 1;

	backupUsers;

	user_io.open(dataFile, user_io.in_file, dataFileName);
	user_io.delete(dataFile);
	user_io.create(dataFile, user_io.out_file, dataFileName);
	for i in 1..numUsers loop
	    user_io.write(dataFile, users(i));
	end loop;
	user_io.close(dataFile);
	unauthenticate;
	return true;

    end deleteUser;

    procedure backupUsers is
	backupFile : user_io.file_type;
    begin
	if initialized = false then
	    init;
	end if;
	begin
	    user_io.open(backupFile, user_io.in_file, backupFileName);
	    user_io.delete(backupFile);
	exception
	    when others => null;
	end;
	
	user_io.create(backupFile, user_io.out_file, backupFileName);
        for i in 1..numUsers loop
	    user_io.write(backupFile, users(i));
	end loop;

	user_io.close(backupFile);
    end backupUsers;

    function authenticate (username : in vstring; password : in vstring) return Boolean is
    begin
	if initialized = false then
	    init;
	end if;
	for i in 1..numUsers loop
	    if vcompare(username, users(i).username) = true and vcompare(password, users(i).password) = true then
	    	currentUser := users(i);
	    	return true;
	    end if;
	end loop;
	return false;
    end authenticate;

    procedure unauthenticate is
    begin
	currentUser := null_user;
    end unauthenticate;


    function getCurrentID return Integer is
    begin
	return currentUser.ID;
    end;

    function getIdFromUsername (username : vstring) return Integer is
    begin
	if initialized = false then
	    init;
	end if;
	for i in 1..numUsers loop
	    if vcompare(users(i).username, username) = true then
		return users(i).ID;
	    end if;
	end loop;
	raise user_not_found;
    end getIdFromUsername;
	    	    
end authentication;
